package com.kaifamiao;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

public class DButils<T> {

    private static String driver;
    private static String url;
    private static String user;
    private static String password;

    private static Connection connection;
    private static PreparedStatement preparedStatement;
    private static ResultSet resultSet;


    static {
        try {
            // 1.读取配置文件
            Properties properties = new Properties();
            InputStream inputStream = DButils.class.getResourceAsStream("/db.properties");
            properties.load(inputStream);
            driver =properties.getProperty("driver");
            url = properties.getProperty("url");
            user = properties.getProperty("user");
            password = properties.getProperty("password");
            // 2.加载数据库驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取数据库连接
     * @return
     */
    private Connection getConnection() {
        try {
            return DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 查询所有记录，返回一个list
     * @param sql
     * @param clazz
     * @param objects
     * @return
     */
    public List<T> selectAll(String sql, Class clazz, Object... objects) {
        try {
            ArrayList<T> list = new ArrayList<>();
            // 获取结果集
            resultSet = executeQuery(sql, objects);
            // 根据反射获取构造函数
            Constructor constructor = clazz.getDeclaredConstructor(null);
            // 获取原型数据
            ResultSetMetaData metaData = resultSet.getMetaData();
            // 获取所有属性
            Field[] declaredFields = clazz.getDeclaredFields();
            // 封装到实体对象中
            while (resultSet.next()) {
                // 创建对象
                Object object = constructor.newInstance(null);
                // 解析结果集
                for (int i = 0; i < declaredFields.length; i++) {
                    Field field = declaredFields[i];
                    String name = field.getName();
                    Object value = resultSet.getObject(name);
                    field.setAccessible(true);
                    field.set(object, value);
                }
                // 添加到集合中
                list.add((T)object);
            }
            return list;
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } finally {
            close(resultSet,preparedStatement,connection);
        }
        return null;
    }

    /**
     * 查询结果集
     * @param sql
     * @param objects
     * @return
     */
    private ResultSet executeQuery(String sql, Object[] objects) {
        try {
            // 获取连接
            connection = getConnection();
            // 获取sql执行对象
            preparedStatement = connection.prepareStatement(sql);
            // 给占位符赋值
            setObject(objects);
            // 执行并返回结果
            return preparedStatement.executeQuery();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 给占位符赋值
     * @param objects
     */
    private void setObject(Object[] objects) {
        if (objects == null) {
            return;
        }
        for (int i = 0; i < objects.length; i++) {
            try {
                preparedStatement.setObject(i + 1, objects[i]);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 关闭资源
     * @param resultSet
     * @param preparedStatement
     * @param connection
     */
    public void close(ResultSet resultSet, PreparedStatement preparedStatement, Connection connection) {
        try {
            if (resultSet != null && !resultSet.isClosed()) {
                resultSet.close();
                resultSet = null;
            }
            if (preparedStatement != null && !preparedStatement.isClosed()) {
                preparedStatement.close();
                preparedStatement = null;
            }
            if (connection != null && !connection.isClosed()) {
                connection.close();
                connection = null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

}
